import { env } from '../utils/env';
import { logger } from '../utils/logger';
import { execSync } from 'child_process';
import * as fs from 'fs';
import * as path from 'path';
import * as os from 'os';

export interface GitConfig {
  repository: string;
  branch: string;
  username?: string;
  token?: string;
  sshKey?: string;
  clonePath?: string;
  updateStrategy?: 'clone' | 'pull' | 'reset';
}

export class GitService {
  private config: GitConfig;

  constructor(config?: Partial<GitConfig>) {
    // 首先设置基本配置
    this.config = {
      repository: config?.repository || env.gitlab.repository,
      branch: config?.branch || env.gitlab.branch,
      username: config?.username || env.gitlab.username,
      token: config?.token || env.gitlab.token,
      sshKey: config?.sshKey || env.gitlab.sshKey,
      clonePath: config?.clonePath || path.join(env.storage.repositoryPath, this.getRepositoryName(config?.repository || env.gitlab.repository)),
      updateStrategy: config?.updateStrategy || 'clone',
    };

    // 验证必要的配置
    if (!this.config.repository) {
      throw new Error('Repository URL is required');
    }
    if (!this.config.branch) {
      throw new Error('Branch is required');
    }
    if (!this.config.clonePath) {
      throw new Error('Clone path is required');
    }
    if (!this.config.token && !this.config.sshKey) {
      throw new Error('Either GitLab token or SSH key is required');
    }
  }

  private getRepositoryName(repositoryUrl: string): string {
    const match = repositoryUrl.match(/\/([^\/]+)\.git$/);
    return match ? match[1] : path.basename(repositoryUrl);
  }

  /**
   * 获取仓库本地路径
   * @returns 仓库本地路径
   */
  public getRepoPath(): string {
    return this.config.clonePath || '';
  }

  private buildAuthUrl(): string {
    const { repository, token } = this.config;
    
    try {
      // 构建带认证的 URL
      const authUrl = repository.replace('https://', `https://gitlab-ci-token:${token}@`);
      
      // 记录 URL（隐藏 token）
      const logUrl = authUrl.replace(token || '', '****');
      logger.info('仓库访问地址:', { url: logUrl });
      
      return authUrl;
    } catch (error) {
      logger.error('构建认证 URL 失败:', { 
        错误信息: error instanceof Error ? error.message : String(error)
      });
      throw error;
    }
  }

  private isGitRepository(dir: string): boolean {
    try {
      return fs.existsSync(path.join(dir, '.git'));
    } catch (error) {
      return false;
    }
  }

  async cloneOrUpdate(): Promise<void> {
    const { clonePath } = this.config;
    if (!clonePath) {
      throw new Error('Clone path is required');
    }
    
    try {
      if (!this.isGitRepository(clonePath)) {
        await this.clone();
      } else {
        await this.update();
      }
    } catch (error) {
      logger.error('Git 操作失败:', { 错误信息: error instanceof Error ? error.message : String(error) });
      throw error;
    }
  }

  private async clone(): Promise<void> {
    const { clonePath, branch } = this.config;
    if (!clonePath) {
      throw new Error('Clone path is required');
    }
    
    logger.info(`开始克隆仓库到: ${clonePath}`);
    
    try {
      // 检查目标目录是否已存在
      if (fs.existsSync(clonePath)) {
        logger.warn('目标目录已存在，将尝试更新仓库');
        return this.update();
      }

      const gitUrl = this.buildAuthUrl();

      // 执行克隆操作
      logger.info(`正在克隆 ${branch} 分支...`);
      execSync(`git clone -b ${branch} "${gitUrl}" "${clonePath}"`, {
        stdio: 'inherit',
        env: {
          ...process.env,
          GIT_TERMINAL_PROMPT: '0',
          GIT_ASKPASS: 'echo'
        }
      });

      logger.info('仓库克隆成功');
    } catch (error) {
      logger.error('仓库克隆失败:', { 
        错误信息: error instanceof Error ? error.message : String(error),
        仓库路径: clonePath,
        分支: branch
      });
      throw error;
    }
  }

  private async update(): Promise<void> {
    const { clonePath, branch } = this.config;
    if (!clonePath) {
      throw new Error('Clone path is required');
    }
    
    logger.info(`开始更新仓库: ${clonePath}`);
    
    try {
      const gitUrl = this.buildAuthUrl();
      
      // 1. 更新远程 URL
      logger.info('更新远程仓库地址...');
      execSync(`cd "${clonePath}" && git remote set-url origin "${gitUrl}"`, {
        stdio: 'pipe',
        env: {
          ...process.env,
          GIT_TERMINAL_PROMPT: '0',
          GIT_ASKPASS: 'echo'
        }
      });

      // 2. 拉取最新代码
      logger.info(`正在从 ${branch} 分支拉取最新代码...`);
      execSync(`cd "${clonePath}" && git pull origin ${branch}`, {
        stdio: 'inherit',
        env: {
          ...process.env,
          GIT_TERMINAL_PROMPT: '0',
          GIT_ASKPASS: 'echo'
        }
      });

      logger.info('仓库更新成功');
    } catch (error) {
      logger.error('仓库更新失败:', { 
        错误信息: error instanceof Error ? error.message : String(error),
        仓库路径: clonePath,
        分支: branch
      });
      throw error;
    }
  }

  async getRepositoryInfo(): Promise<{
    currentBranch: string;
    commitHash: string;
    remoteUrl: string;
    lastUpdate: string;
  }> {
    const { clonePath } = this.config;
    if (!clonePath) {
      throw new Error('Clone path is required');
    }
    
    try {
      const currentBranch = execSync(`cd ${clonePath} && git rev-parse --abbrev-ref HEAD`).toString().trim();
      const commitHash = execSync(`cd ${clonePath} && git rev-parse HEAD`).toString().trim();
      const remoteUrl = execSync(`cd ${clonePath} && git remote get-url origin`).toString().trim();
      const lastUpdate = execSync(`cd ${clonePath} && git log -1 --format=%cd`).toString().trim();
      
      return {
        currentBranch,
        commitHash,
        remoteUrl,
        lastUpdate,
      };
    } catch (error) {
      logger.error('获取仓库信息失败:', { 错误信息: error instanceof Error ? error.message : String(error) });
      throw error;
    }
  }

  async cleanup(): Promise<void> {
    const { clonePath } = this.config;
    if (!clonePath) {
      throw new Error('Clone path is required');
    }
    
    try {
      // 清理未跟踪的文件
      execSync(`cd ${clonePath} && git clean -fd`, { stdio: 'inherit' });
      // 重置本地修改
      execSync(`cd ${clonePath} && git reset --hard`, { stdio: 'inherit' });
      
      logger.info('仓库清理成功');
    } catch (error) {
      logger.error('仓库清理失败:', { 错误信息: error instanceof Error ? error.message : String(error) });
      throw error;
    }
  }

  public async ensureRepo(): Promise<void> {
    const { clonePath } = this.config;
    if (!clonePath) {
      throw new Error('Clone path is required');
    }
    
    try {
      logger.info('检查仓库状态...');
      
      if (!fs.existsSync(clonePath)) {
        logger.info('仓库不存在，开始克隆...');
        await this.clone();
      } else {
        logger.info('仓库已存在，开始更新...');
        await this.update();
      }
    } catch (error) {
      logger.error('仓库操作失败:', {
        错误信息: error instanceof Error ? error.message : String(error),
        仓库路径: clonePath
      });
      throw error;
    }
  }
} 